Quick overview

Current status

#library(nCov2019)
library(leaflet)
library(dplyr)
library(ggplot2)
library(plotly)
library(scales)
library(xts)
library(dygraphs)
library(corrplot)
library(lubridate)
library(fmsb)
COVID<-read.csv("covid_19_data.csv")
COVID_2<-read.csv("COVID19_10-Apr.csv")

Format date:

Date<-as.Date(COVID_2$Date, format="%m/%d/%y") 

COVID_2$Date2<-Date
COVID_updated<-COVID_2 %>% filter(Date2==max(Date2))
leaflet(width = "100%") %>% 
  addProviderTiles("CartoDB.DarkMatter") %>% 
  setView(lng = 0, lat = 10, zoom = 1.5) %>% 
  addCircleMarkers(data = COVID_updated, 
                   lng = ~ Long,
                   lat = ~ Lat,
                   radius = ~ log(Confirmed+1),
                   color = rgb(218/255,65/255,56/255),
                   fillOpacity = ~ ifelse(Confirmed > 0, 1, 0),
                   stroke = FALSE,
                   label = ~ paste(Province.State,",",Country.Region, ": ", Confirmed)
                   )

Current top 10 countries:

COVID_top<-COVID_2 %>% filter(Date2==max(Date2)) %>% 
  group_by(Country.Region) %>% summarise(Total_confirmed=sum(Confirmed)) %>% 
  top_n(10,Total_confirmed) %>% arrange(desc(Total_confirmed))
plot<-ggplot(data=COVID_top
       , aes(x=Total_confirmed,y=reorder(Country.Region,Total_confirmed))) +
  geom_bar(stat ="identity",alpha=0.8,fill="firebrick3") +
  geom_text(aes(label=Total_confirmed), vjust=0.5, hjust=0.9,color="black", size=3.5) +
  scale_x_continuous(labels = comma) +
  labs(title = paste("Top 10 countries with confirmed cases as of ",max(COVID_2$Date2)),
       x = "Confirmed cases",
       y = "Country") +
  theme_minimal()

ggplotly(plot,tooltip = c("x"),width=750)

Time distribution:

COVID_2_Day<- COVID_2 %>% group_by(Date2) %>% summarise(World_confirmed=sum(Confirmed),
                                                        World_deaths=sum(Deaths),
                                                        World_recovered=sum(Recovered))


COVID_Day_confirmed_series<-xts(COVID_2_Day$World_confirmed, order.by=COVID_2_Day$Date2)
COVID_Day_deaths_series<-xts(COVID_2_Day$World_deaths, order.by=COVID_2_Day$Date2)
COVID_Day_recovered_series<-xts(COVID_2_Day$World_recovered, order.by=COVID_2_Day$Date2)

Day_summary<-cbind(COVID_Day_confirmed_series,COVID_Day_deaths_series,COVID_Day_recovered_series)
dygraph(Day_summary, main = "SARS-COV2-outbreak: Total worldwide cases", 
        xlab="Date", ylab="Total cases",width = 750) %>% 
  dySeries("COVID_Day_confirmed_series", "Total cases",drawPoints = TRUE, 
           pointSize = 3, color=rgb(53/255,116/255,199/255)) %>% 
  dySeries("COVID_Day_deaths_series", "Total deaths",drawPoints = TRUE, 
           pointSize = 3, color=rgb(189/255,55/255,48/255)) %>% 
  dySeries("COVID_Day_recovered_series", "Total recovered",drawPoints = TRUE, 
           pointSize = 3, color=rgb(69/255,136/255,51/255)) %>% 
  dyRangeSelector()
New_count<-function(x)
{
  Daily_cases<-numeric(length(x))
  
  for(i in length(x):2)
  {
    Daily_cases[i]=x[i] - x[i-1]
  }
  return(Daily_cases)
}

New_cases<-New_count(COVID_2_Day$World_confirmed)
New_deaths<-New_count(COVID_2_Day$World_deaths)
New_recovered<-New_count(COVID_2_Day$World_recovered)
COVID_New_confirmed_series<-xts(New_cases, order.by=COVID_2_Day$Date2)
COVID_New_deaths_series<-xts(New_deaths, order.by=COVID_2_Day$Date2)
COVID_New_recovered_series<-xts(New_recovered, order.by=COVID_2_Day$Date2)

New_summary<-cbind(COVID_New_confirmed_series,COVID_New_deaths_series,COVID_New_recovered_series)
dygraph(New_summary, main = "SARS-COV2-outbreak: Total worldwide cases", 
        xlab="Date", ylab="Novel coronavirus cases",width = 750) %>% 
  dySeries("COVID_New_confirmed_series", "New cases",drawPoints = TRUE, 
           pointSize = 3, color=rgb(53/255,116/255,199/255)) %>% 
  dySeries("COVID_New_deaths_series", "New deaths",drawPoints = TRUE, 
           pointSize = 3, color=rgb(189/255,55/255,48/255)) %>% 
  dySeries("COVID_New_recovered_series", "New recovered",drawPoints = TRUE, 
           pointSize = 3, color=rgb(69/255,136/255,51/255)) %>% 
  dyRangeSelector()

Team members countries total cases:

COVID_2_Day_Lebanon<- COVID_2 %>% 
  filter(Country.Region %in% c("Lebanon")) %>% 
  group_by(Date2) %>% summarise(World_confirmed=sum(Confirmed))

COVID_2_Day_Chile<- COVID_2 %>% 
  filter(Country.Region %in% c("Chile")) %>% 
  group_by(Date2) %>% summarise(World_confirmed=sum(Confirmed))

COVID_2_Day_Colombia<- COVID_2 %>% 
  filter(Country.Region %in% c("Colombia")) %>% 
  group_by(Date2) %>% summarise(World_confirmed=sum(Confirmed))

COVID_2_Day_CostaRica<- COVID_2 %>% 
  filter(Country.Region %in% c("Costa Rica")) %>% 
  group_by(Date2) %>% summarise(World_confirmed=sum(Confirmed))


COVID_Day_series_Lebanon<-xts(COVID_2_Day_Lebanon$World_confirmed, order.by=COVID_2_Day_Lebanon$Date2)
COVID_Day_series_Chile<-xts(COVID_2_Day_Chile$World_confirmed, order.by=COVID_2_Day_Chile$Date2)
COVID_Day_series_Colombia<-xts(COVID_2_Day_Colombia$World_confirmed, order.by=COVID_2_Day_Colombia$Date2)
COVID_Day_series_CostaRica<-xts(COVID_2_Day_CostaRica$World_confirmed, order.by=COVID_2_Day_CostaRica$Date2)

Our_Countries<-cbind(COVID_Day_series_Lebanon,COVID_Day_series_Chile,COVID_Day_series_Colombia,COVID_Day_series_CostaRica)
dygraph(Our_Countries, main = "SARS-COV2-outbreak: Total cases by country", xlab="Date", ylab="Total cases",width = 750) %>% 
  dySeries("COVID_Day_series_Lebanon", "Lebanon",drawPoints = TRUE, 
           pointSize = 3, color=rgb(0,0,3/255)) %>% 
  dySeries("COVID_Day_series_Chile", "Chile",drawPoints = TRUE, 
           pointSize = 3,color=rgb(120/255,28/255,109/255)) %>% 
  dySeries("COVID_Day_series_Colombia", "Colombia",drawPoints = TRUE, 
           pointSize = 3,color=rgb(237/255,105/255,37/255)) %>% 
  dySeries("COVID_Day_series_CostaRica", "Costa Rica",drawPoints = TRUE,
           pointSize = 3,color=rgb(204/255,197/255,126/255)) %>% 
  dyRangeSelector()
New_Lebanon<-New_count(COVID_2_Day_Lebanon$World_confirmed)
New_Chile<-New_count(COVID_2_Day_Chile$World_confirmed)
New_Colombia<-New_count(COVID_2_Day_Colombia$World_confirmed)
New_CostaRica<-New_count(COVID_2_Day_CostaRica$World_confirmed)

COVID_New_series_Lebanon<-xts(New_Lebanon, order.by=COVID_2_Day_Lebanon$Date2)
COVID_New_series_Chile<-xts(New_Chile, order.by=COVID_2_Day_Chile$Date2)
COVID_New_series_Colombia<-xts(New_Colombia, order.by=COVID_2_Day_Colombia$Date2)
COVID_New_series_CostaRica<-xts(New_CostaRica, order.by=COVID_2_Day_CostaRica$Date2)

Our_New_Countries<-cbind(COVID_New_series_Lebanon,COVID_New_series_Chile,COVID_New_series_Colombia,COVID_New_series_CostaRica)
dygraph(Our_New_Countries, main = "SARS-COV2-outbreak: New cases by country", xlab="Date", ylab="Total cases",width = 750) %>% 
  dySeries("COVID_New_series_Lebanon", "Lebanon",drawPoints = TRUE, 
           pointSize = 3, color=rgb(0,0,3/255)) %>% 
  dySeries("COVID_New_series_Chile", "Chile",drawPoints = TRUE, 
           pointSize = 3,color=rgb(120/255,28/255,109/255)) %>% 
  dySeries("COVID_New_series_Colombia", "Colombia",drawPoints = TRUE, 
           pointSize = 3,color=rgb(237/255,105/255,37/255)) %>% 
  dySeries("COVID_New_series_CostaRica", "Costa Rica",drawPoints = TRUE,
           pointSize = 3,color=rgb(204/255,197/255,126/255)) %>% 
  dyRangeSelector()

Looking for correlations

fig <- plot_ly(COVID_updated, x = ~Confirmed, y = ~Deaths, z = ~Recovered, width=750) %>% 
  add_markers(text= ~Country.Region ,hoverinfo= "text",
              marker = list(color=rgb(189/255,55/255,48/255))) %>% 
  layout(title="Confirmed cases Vs. Deaths Vs. Recovered", scene = list(
                    xaxis = list(title = 'Confirmed'),
                     yaxis = list(title = 'Deaths'),
                     zaxis = list(title = 'Recovered'))) 
fig

For the number of cases

Human Development Index

HDI<-read.csv("Human Development Index (HDI)_2.csv",sep=";",dec=",")
COVID_Country<-COVID_2 %>% filter(Date2==max(Date2)) %>% 
  group_by(Country.Region) %>% summarise(Total_confirmed=sum(Confirmed),
                                         Total_deaths=sum(Deaths),
                                         Total_Recovered=sum(Recovered))

Remove after parentheses:

HDI$Country_2<-gsub("\\s*\\([^\\)]+\\)","",as.character(HDI$Country))
HDI$Country_2[HDI$Country_2=="United States"]<-"US"
HDI$Country_2[HDI$Country_2=="Korea"]<-"South Korea"

Population:

Population<-read.csv("World_population.csv",sep=";",dec=",")

Remove after commma:

Population$Country_Name_2<-gsub(",.*", "", as.character(Population$Country_Name))
Population$Country_Name_2[Population$Country_Name_2=="United States"]<-"US"
Population$Country_Name_2[Population$Country_Code=="KOR"]<-"South Korea"
Population$Country_Name_2[Population$Country_Code=="CZE"]<-"Czechia"

Natural Join:

COVID_3<- COVID_Country %>% inner_join(HDI,by=c("Country.Region"="Country_2")) %>% 
  inner_join(Population,by=c("Country.Region"="Country_Name_2")) %>% 
  select(Country.Region,Total_confirmed,Total_deaths,Total_Recovered,HDI_Rank_2018,Year_2018,
         Country_Code,Population_2018) %>% 
  mutate(Cases_million=(Total_confirmed/Population_2018)*1000000,
         Recovered_percentage=(Total_Recovered/Total_confirmed)*100)  

COVID_3<-COVID_3[!is.na(COVID_3$Population_2018),]

Plot the Human Development Index(HDI) Vs. the number of cases (applying a log transformation), and the proportion of recovered cases:

plot<-ggplot(data=COVID_3,aes(x=log(Cases_million),y=Year_2018,
                        size=Recovered_percentage,text=Country.Region)) +
  geom_point(color="black",fill=rgb(237/255,105/255,37/255),shape=21,alpha=0.6) +
  scale_size(range = c(3,15), name="Recovered \n percentage") +
  theme_minimal() + 
  theme(legend.position="bottom") +
  labs(title="HDI Vs. logarithmus of COVID-19 cases by million inhabitants \n and proportion of recovered",
       x="ln(Cases/1M population)",
       y="HDI")

ggplotly(plot,tooltip = c("text"),width=750)
COVID_numeric_1<-COVID_3 %>% mutate(Log_cases=log(Cases_million),
                                    Death_percentage=(Total_deaths/Total_confirmed)*100) %>% 
  select(Log_cases,Recovered_percentage,Death_percentage,Year_2018)

corrplot(cor(COVID_numeric_1),method = "number",tl.col="black",tl.srt=15,
         col=colorRampPalette(c(rgb(204/255,197/255,126/255),rgb(237/255,105/255,37/255)))(200))

Health expenditure (% of GDP)

Health_expenditure<-read.csv("Health_expenditure_GDP.csv",sep=";",dec=".")
Health_expenditure$Country_2<-gsub("\\s*\\([^\\)]+\\)","",
                                   as.character(Health_expenditure$Country))
Health_expenditure$Country_2[Health_expenditure$Country_2=="United States"]<-"US"
Health_expenditure$Country_2[Health_expenditure$Country_2=="Korea"]<-"South Korea"
COVID_3<- COVID_3 %>% inner_join(Health_expenditure,by=c("Country.Region"="Country_2")) %>% select(-c("Country"))

#write.csv(COVID_3,"COVID_Covariables.csv")
plot<-ggplot(data=COVID_3,aes(x=log(Cases_million),y=Expenditure_2016,
                        size=Recovered_percentage,text=Country.Region)) +
  geom_point(color="black",fill=rgb(204/255,197/255,126/255),shape=21,alpha=0.6) +
  scale_size(range = c(3,15), name="Recovered \n percentage") +
  theme_minimal() + 
  theme(legend.position="bottom") +
  labs(title="Health expenditure (% of GDP) Vs. logarithmus of COVID-19 cases by million inhabitants \n and proportion of recovered",
       x="ln(Cases/1M population)",
       y="% of GDP in health")

ggplotly(plot,tooltip = c("text"),width=750)

Temperature

Temperature<-read.csv("GlobalLandTemperaturesByCountry.csv",sep=";")
Date_Temp<-as.Date(Temperature$dt, format="%d/%m/%Y") 

Temperature$Date_Temp<-Date_Temp

Extract month, filter IQ (Jan, Feb and Mar) and obtain the average IQ temperature:

Temperature<- Temperature %>% mutate(Month=month(Temperature$Date_Temp,label =TRUE),
                                     Year=year(Temperature$Date_Temp)) %>% 
  filter(Month %in% c("Jan","Feb","Mar") & Year>=2000)  %>% 
  group_by(Country) %>% summarise(Avg_IQ_temperature=mean(AverageTemperature))

Temperature<-Temperature[!is.na(Temperature$Avg_IQ_temperature),]
Temperature$Country_2<-gsub("\\s*\\([^\\)]+\\)","",
                                   as.character(Temperature$Country))
Temperature$Country_2[Temperature$Country_2=="United States"]<-"US"
Temperature$Country_2[Temperature$Country_2=="Korea"]<-"South Korea"
COVID_3<- COVID_3 %>% inner_join(Temperature,by=c("Country.Region"="Country_2")) %>% select(-c("Country"))

#write.csv(COVID_3,"COVID_Covariables.csv")
plot<-ggplot(data=COVID_3,aes(x=log(Cases_million),y=Avg_IQ_temperature,
                        size=Recovered_percentage,text=Country.Region)) +
  geom_point(color="black",fill=rgb(120/255,28/255,109/255),shape=21,alpha=0.6) +
  scale_size(range = c(3,15), name="Recovered \n percentage") +
  theme_minimal() + 
  theme(legend.position="bottom") +
  labs(title="Average IQ temperature Vs. logarithmus of COVID-19 cases by million inhabitants \n and proportion of recovered",
       x="ln(Cases/1M population)",
       y="Temperature (Celcius)")

ggplotly(plot,tooltip = c("text"),width=750)

For the number of deaths

###DTP immunization

DTP_immunization<-read.csv("Infants_lacking_immunization_DTP.csv",sep=";")

Remove after parentheses:

DTP_immunization$Country_2<-gsub("\\s*\\([^\\)]+\\)","",
                                 as.character(DTP_immunization$Country))
DTP_immunization$Country_2[DTP_immunization$Country_2=="United States"]<-"US"
DTP_immunization$Country_2[DTP_immunization$Country_2=="Korea"]<-"South Korea"
COVID_4<- COVID_Country %>% inner_join(DTP_immunization,
                                       by=c("Country.Region"="Country_2")) %>% 
  select(Country.Region,Total_confirmed,Total_deaths,Total_Recovered,
         Lack_DTP_inmmunization_2018) %>% 
  mutate(Recovered_percentage=(Total_Recovered/Total_confirmed)*100,
         Death_rate=(Total_deaths/Total_confirmed)*100)
plot<-ggplot(data=COVID_4,aes(x=Death_rate,y=Lack_DTP_inmmunization_2018,
                        size=Recovered_percentage,text=Country.Region)) +
  geom_point(color="black",fill=rgb(204/255,197/255,126/255),shape=21,alpha=0.6) +
  scale_size(range = c(3,15), name="Recovered \n percentage") +
  theme_minimal() + 
  theme(legend.position="bottom") +
  labs(title="% infants lacking DTP immunization Vs. death rate and \n proportion of recovered",
       x="Novel coronavirus death rate",
       y="% of infants")

ggplotly(plot,tooltip = c("text"),width=750)

Infants lacking immunization, measles (% of one-year-olds)

Measles<-read.csv("Measles_immunization.csv",sep=";",dec=".")
Measles$Country_2<-gsub("\\s*\\([^\\)]+\\)","",as.character(Measles$Country))
Measles$Country_2[Measles$Country_2=="United States"]<-"US"
Measles$Country_2[Measles$Country_2=="Korea"]<-"South Korea"
COVID_4<- COVID_4 %>% inner_join(Measles,by=c("Country.Region"="Country_2")) %>% select(-c("Country"))
ggplot(COVID_4, aes(y=Measles_2018)) + 
  geom_boxplot(fill="dodgerblue4",outlier.shape = 21, 
               outlier.fill = "firebrick",alpha=0.75) +
  ggtitle("Boxplot of % infants lacking measles immunization") + ylab("% of infants") +
  theme_minimal()

ggplot(COVID_4, aes(Measles_2018)) + 
  geom_histogram(fill="dodgerblue4",bins=20,alpha=0.8) +
  ggtitle("Histogram of % infants lacking measles immunization") + 
  xlab("% of infants") + 
  ylab("Count") +
  theme_minimal()

plot<-ggplot(data=COVID_4,aes(x=Death_rate,y=Measles_2018,
                        size=Recovered_percentage,text=Country.Region)) +
  geom_point(color="black",fill=rgb(237/255,105/255,37/255),shape=21,alpha=0.6) +
  scale_size(range = c(3,15), name="Recovered \n percentage") +
  theme_minimal() + 
  theme(legend.position="bottom") +
  labs(title="% infants lacking measles immunization Vs. fatality rate \n and proportion of recovered",
       x="Fatality rate (%)",
       y="% of infants")

ggplotly(plot,tooltip = c("text"),width=750)

Fitting a regression model

Transforming with ln and converting temperature as kelvin:

Mod1<-lm(log(COVID_3$Cases_million)~log(COVID_3$Year_2018)+log(COVID_3$Measles_2018)+
           log(COVID_3$Expenditure_2016)+log(COVID_3$Avg_IQ_temperature+273.15))
summary(Mod1)

Call:
lm(formula = log(COVID_3$Cases_million) ~ log(COVID_3$Year_2018) + 
    log(COVID_3$Measles_2018) + log(COVID_3$Expenditure_2016) + 
    log(COVID_3$Avg_IQ_temperature + 273.15))

Residuals:
    Min      1Q  Median      3Q     Max 
-3.7927 -0.8026 -0.0988  0.7685  4.6646 

Coefficients:
                                         Estimate Std. Error t value Pr(>|t|)    
(Intercept)                              28.91233   18.71752   1.545  0.12462    
log(COVID_3$Year_2018)                    8.09219    0.65485  12.357  < 2e-16 ***
log(COVID_3$Measles_2018)                 0.07961    0.11782   0.676  0.50030    
log(COVID_3$Expenditure_2016)             1.00758    0.30867   3.264  0.00137 ** 
log(COVID_3$Avg_IQ_temperature + 273.15) -4.26198    3.29459  -1.294  0.19786    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1.36 on 144 degrees of freedom
Multiple R-squared:  0.723, Adjusted R-squared:  0.7153 
F-statistic: 93.96 on 4 and 144 DF,  p-value: < 2.2e-16

Stepwise with AIC critertion:

Mod2<-step(Mod1,direction = "both")
Start:  AIC=88.41
log(COVID_3$Cases_million) ~ log(COVID_3$Year_2018) + log(COVID_3$Measles_2018) + 
    log(COVID_3$Expenditure_2016) + log(COVID_3$Avg_IQ_temperature + 
    273.15)

                                           Df Sum of Sq    RSS     AIC
- log(COVID_3$Measles_2018)                 1     1.326 252.72  87.188
<none>                                                  251.39  88.410
- log(COVID_3$Avg_IQ_temperature + 273.15)  1     3.627 255.02  88.530
- log(COVID_3$Expenditure_2016)             1    19.903 271.29  97.687
- log(COVID_3$Year_2018)                    1   267.232 518.62 193.587

Step:  AIC=87.19
log(COVID_3$Cases_million) ~ log(COVID_3$Year_2018) + log(COVID_3$Expenditure_2016) + 
    log(COVID_3$Avg_IQ_temperature + 273.15)

                                           Df Sum of Sq    RSS     AIC
<none>                                                  252.72  87.188
- log(COVID_3$Avg_IQ_temperature + 273.15)  1     3.451 256.17  87.196
+ log(COVID_3$Measles_2018)                 1     1.326 251.39  88.410
- log(COVID_3$Expenditure_2016)             1    20.945 273.66  96.973
- log(COVID_3$Year_2018)                    1   310.195 562.91 203.715
summary(Mod2)

Call:
lm(formula = log(COVID_3$Cases_million) ~ log(COVID_3$Year_2018) + 
    log(COVID_3$Expenditure_2016) + log(COVID_3$Avg_IQ_temperature + 
    273.15))

Residuals:
    Min      1Q  Median      3Q     Max 
-3.6304 -0.8232 -0.0390  0.8247  4.5290 

Coefficients:
                                         Estimate Std. Error t value Pr(>|t|)    
(Intercept)                               30.1643    18.2214   1.655 0.100014    
log(COVID_3$Year_2018)                     7.6731     0.5772  13.295  < 2e-16 ***
log(COVID_3$Expenditure_2016)              1.0349     0.2996   3.455 0.000724 ***
log(COVID_3$Avg_IQ_temperature + 273.15)  -4.4971     3.2069  -1.402 0.162977    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1.325 on 144 degrees of freedom
Multiple R-squared:  0.7221,    Adjusted R-squared:  0.7163 
F-statistic: 124.7 on 3 and 144 DF,  p-value: < 2.2e-16

Normality of residuals:

hist(Mod2$residuals)

shapiro.test(Mod2$residuals)

    Shapiro-Wilk normality test

data:  Mod2$residuals
W = 0.98758, p-value = 0.2094

Prediction power: separate between training and testing:

set.seed(179819)
Sample <- sample(1:length(COVID_3$Cases_million),length(COVID_3$Cases_million)*0.20)
t.testing<- COVID_3[Sample,]
t.training<- COVID_3[-Sample,]

Transform the training and testing variables as before:

t.training<-t.training %>% mutate(Cases_million_log=log(Cases_million),HDI_log=log(Year_2018),
                      GDP_log=log(Expenditure_2016),
                      Temperature_log_kelvin=log(Avg_IQ_temperature+273.15)) 

t.training<-t.training[,14:17]

t.testing<-t.testing %>% mutate(Cases_million_log=log(Cases_million),HDI_log=log(Year_2018),
                      GDP_log=log(Expenditure_2016),
                      Temperature_log_kelvin=log(Avg_IQ_temperature+273.15)) 

t.testing<-t.testing[,14:17]

Fit the same model with training

Mod3<-lm(Cases_million_log~., data=t.training)
summary(Mod3)

Call:
lm(formula = Cases_million_log ~ ., data = t.training)

Residuals:
    Min      1Q  Median      3Q     Max 
-3.4682 -0.7667 -0.0638  0.7399  4.3449 

Coefficients:
                       Estimate Std. Error t value Pr(>|t|)    
(Intercept)             39.0811    18.5629   2.105  0.03744 *  
HDI_log                  7.1009     0.6266  11.332  < 2e-16 ***
GDP_log                  1.0890     0.3331   3.270  0.00142 ** 
Temperature_log_kelvin  -6.1107     3.2665  -1.871  0.06393 .  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1.252 on 115 degrees of freedom
Multiple R-squared:  0.7275,    Adjusted R-squared:  0.7204 
F-statistic: 102.4 on 3 and 115 DF,  p-value: < 2.2e-16

Error functions:

# Residual Sum of Square (RSS)
RSS<-function(Pred,Actual) {
  ss<-sum((Actual-Pred)^2)
  return(ss)
}

# Residual Standard Error (RSE)
RSE<-function(Pred,Real,NumPred) {
  N<-length(Real)-NumPred-1  
  ss<-sqrt((1/N)*RSS(Pred,Real))
  return(ss)
}
# Mean Squared Error 
MSE <- function(Pred,Actual) {
  N<-length(Actual)
  ss<-(1/N)*RSS(Pred,Actual)
  return(ss)
}

# Relative error
RelativeError<-function(Pred,Actual) {
  ss<-sum(abs(Actual-Pred))/sum(abs(Actual))
  return(ss)
}

Prediction:

Pred<-predict(Mod3,t.testing)

Errors:

RSS_Mod3<-RSS(Pred,t.testing$Cases_million_log)
RSE_Mod3<-RSE(Pred,t.testing$Cases_million_log,dim(t.testing)[2]-1)
MSE_Mod3<-MSE(Pred,t.testing$Cases_million_log)
RelativeError_Mod3<-RelativeError(Pred,t.testing$Cases_million_log)

Mod3_Errors<-c(RSS_Mod3,RSE_Mod3,MSE_Mod3,RelativeError_Mod3)

Now, a model without temperature:

t.training <- t.training %>% select(-Temperature_log_kelvin)
t.testing <- t.testing %>% select(-Temperature_log_kelvin)
Mod4<-lm(Cases_million_log~., data=t.training)
summary(Mod4)

Call:
lm(formula = Cases_million_log ~ ., data = t.training)

Residuals:
    Min      1Q  Median      3Q     Max 
-3.7017 -0.8447  0.0129  0.7149  4.3942 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)   4.3797     0.7074   6.191  9.3e-09 ***
HDI_log       7.6548     0.5582  13.713  < 2e-16 ***
GDP_log       1.2422     0.3263   3.807 0.000227 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1.266 on 116 degrees of freedom
Multiple R-squared:  0.7192,    Adjusted R-squared:  0.7144 
F-statistic: 148.6 on 2 and 116 DF,  p-value: < 2.2e-16

Prediction:

Pred<-predict(Mod4,t.testing)

Errors:

RSS_Mod4<-RSS(Pred,t.testing$Cases_million_log)
RSE_Mod4<-RSE(Pred,t.testing$Cases_million_log,dim(t.testing)[2]-1)
MSE_Mod4<-MSE(Pred,t.testing$Cases_million_log)
RelativeError_Mod4<-RelativeError(Pred,t.testing$Cases_million_log)

Mod4_Errors<-c(RSS_Mod4,RSE_Mod4,MSE_Mod4,RelativeError_Mod4)

Create a radarplot:

Errors<-rbind(Mod3_Errors,Mod4_Errors)

rownames(Errors)<-c("Model with temperature","Model without temperature")

colnames(Errors)<-c("Residual Sum of Square","Residual Standard Error","Mean Squared Error","Relative error")

Errors<-as.data.frame(Errors)

maximum<-apply(Errors,2,max)

minimum<-apply(Errors,2,min)

Errors<-rbind(minimum,Errors)

Errors<-rbind(maximum,Errors)
radarchart(Errors,maxmin=TRUE,axistype=4,axislabcol="slategray4",
           centerzero=FALSE,seg=8,cglcol="gray67",
           pcol=c("dodgerblue2","firebrick2","darkorange2","darkorchid2"),
           plty=1,
           plwd=3,
           title="Error comparison")

legenda <-legend(1.5,1, legend=c("With temperature","Without temperature"),
                 seg.len=-1.4,
                 title="Errors",
                 pch=21, 
                 bty="n" ,lwd=3, y.intersp=1, horiz=FALSE,
                 col=c("dodgerblue2","firebrick2","darkorange2","darkorchid2"))

LS0tCnRpdGxlOiAiQ09WSUQtMTkgT3V0YnJlYWs6IFdvcmxkd2lkZSBhbmFseXNpcyIKYXV0aG9yOiAiQW91biwgQ2FtYXJnbywgTWFydGluZXosUm9kcmlndWV6IgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogMwogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IHRydWUKICAgICAgc21vb3RoX3Njcm9sbDogdHJ1ZQogICAgdGhlbWU6IGNvc21vCiAgICAgCi0tLQohW10oQ29yb25hdmlydXMuanBnKQoKIyBRdWljayBvdmVydmlldwoKIyMgQ3VycmVudCBzdGF0dXMKCgpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0V9CiNsaWJyYXJ5KG5Db3YyMDE5KQpsaWJyYXJ5KGxlYWZsZXQpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShwbG90bHkpCmxpYnJhcnkoc2NhbGVzKQpsaWJyYXJ5KHh0cykKbGlicmFyeShkeWdyYXBocykKbGlicmFyeShjb3JycGxvdCkKbGlicmFyeShsdWJyaWRhdGUpCmxpYnJhcnkoZm1zYikKYGBgCgpgYGB7cn0KQ09WSUQ8LXJlYWQuY3N2KCJjb3ZpZF8xOV9kYXRhLmNzdiIpCkNPVklEXzI8LXJlYWQuY3N2KCJDT1ZJRDE5XzEwLUFwci5jc3YiKQpgYGAKCkZvcm1hdCBkYXRlOgpgYGB7cn0KRGF0ZTwtYXMuRGF0ZShDT1ZJRF8yJERhdGUsIGZvcm1hdD0iJW0vJWQvJXkiKSAKCkNPVklEXzIkRGF0ZTI8LURhdGUKYGBgCgpgYGB7cn0KQ09WSURfdXBkYXRlZDwtQ09WSURfMiAlPiUgZmlsdGVyKERhdGUyPT1tYXgoRGF0ZTIpKQpgYGAKCmBgYHtyLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0KbGVhZmxldCh3aWR0aCA9ICIxMDAlIikgJT4lIAogIGFkZFByb3ZpZGVyVGlsZXMoIkNhcnRvREIuRGFya01hdHRlciIpICU+JSAKICBzZXRWaWV3KGxuZyA9IDAsIGxhdCA9IDEwLCB6b29tID0gMS41KSAlPiUgCiAgYWRkQ2lyY2xlTWFya2VycyhkYXRhID0gQ09WSURfdXBkYXRlZCwgCiAgICAgICAgICAgICAgICAgICBsbmcgPSB+IExvbmcsCiAgICAgICAgICAgICAgICAgICBsYXQgPSB+IExhdCwKICAgICAgICAgICAgICAgICAgIHJhZGl1cyA9IH4gbG9nKENvbmZpcm1lZCsxKSwKICAgICAgICAgICAgICAgICAgIGNvbG9yID0gcmdiKDIxOC8yNTUsNjUvMjU1LDU2LzI1NSksCiAgICAgICAgICAgICAgICAgICBmaWxsT3BhY2l0eSA9IH4gaWZlbHNlKENvbmZpcm1lZCA+IDAsIDEsIDApLAogICAgICAgICAgICAgICAgICAgc3Ryb2tlID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICBsYWJlbCA9IH4gcGFzdGUoUHJvdmluY2UuU3RhdGUsIiwiLENvdW50cnkuUmVnaW9uLCAiOiAiLCBDb25maXJtZWQpCiAgICAgICAgICAgICAgICAgICApCmBgYAoKQ3VycmVudCB0b3AgMTAgY291bnRyaWVzOgpgYGB7cn0KQ09WSURfdG9wPC1DT1ZJRF8yICU+JSBmaWx0ZXIoRGF0ZTI9PW1heChEYXRlMikpICU+JSAKICBncm91cF9ieShDb3VudHJ5LlJlZ2lvbikgJT4lIHN1bW1hcmlzZShUb3RhbF9jb25maXJtZWQ9c3VtKENvbmZpcm1lZCkpICU+JSAKICB0b3BfbigxMCxUb3RhbF9jb25maXJtZWQpICU+JSBhcnJhbmdlKGRlc2MoVG90YWxfY29uZmlybWVkKSkKYGBgCgpgYGB7cn0KcGxvdDwtZ2dwbG90KGRhdGE9Q09WSURfdG9wCiAgICAgICAsIGFlcyh4PVRvdGFsX2NvbmZpcm1lZCx5PXJlb3JkZXIoQ291bnRyeS5SZWdpb24sVG90YWxfY29uZmlybWVkKSkpICsKICBnZW9tX2JhcihzdGF0ID0iaWRlbnRpdHkiLGFscGhhPTAuOCxmaWxsPSJmaXJlYnJpY2szIikgKwogIGdlb21fdGV4dChhZXMobGFiZWw9VG90YWxfY29uZmlybWVkKSwgdmp1c3Q9MC41LCBoanVzdD0wLjksY29sb3I9ImJsYWNrIiwgc2l6ZT0zLjUpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpICsKICBsYWJzKHRpdGxlID0gcGFzdGUoIlRvcCAxMCBjb3VudHJpZXMgd2l0aCBjb25maXJtZWQgY2FzZXMgYXMgb2YgIixtYXgoQ09WSURfMiREYXRlMikpLAogICAgICAgeCA9ICJDb25maXJtZWQgY2FzZXMiLAogICAgICAgeSA9ICJDb3VudHJ5IikgKwogIHRoZW1lX21pbmltYWwoKQoKZ2dwbG90bHkocGxvdCx0b29sdGlwID0gYygieCIpLHdpZHRoPTc1MCkKYGBgCgpUaW1lIGRpc3RyaWJ1dGlvbjoKYGBge3J9CkNPVklEXzJfRGF5PC0gQ09WSURfMiAlPiUgZ3JvdXBfYnkoRGF0ZTIpICU+JSBzdW1tYXJpc2UoV29ybGRfY29uZmlybWVkPXN1bShDb25maXJtZWQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFdvcmxkX2RlYXRocz1zdW0oRGVhdGhzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBXb3JsZF9yZWNvdmVyZWQ9c3VtKFJlY292ZXJlZCkpCgoKQ09WSURfRGF5X2NvbmZpcm1lZF9zZXJpZXM8LXh0cyhDT1ZJRF8yX0RheSRXb3JsZF9jb25maXJtZWQsIG9yZGVyLmJ5PUNPVklEXzJfRGF5JERhdGUyKQpDT1ZJRF9EYXlfZGVhdGhzX3NlcmllczwteHRzKENPVklEXzJfRGF5JFdvcmxkX2RlYXRocywgb3JkZXIuYnk9Q09WSURfMl9EYXkkRGF0ZTIpCkNPVklEX0RheV9yZWNvdmVyZWRfc2VyaWVzPC14dHMoQ09WSURfMl9EYXkkV29ybGRfcmVjb3ZlcmVkLCBvcmRlci5ieT1DT1ZJRF8yX0RheSREYXRlMikKCkRheV9zdW1tYXJ5PC1jYmluZChDT1ZJRF9EYXlfY29uZmlybWVkX3NlcmllcyxDT1ZJRF9EYXlfZGVhdGhzX3NlcmllcyxDT1ZJRF9EYXlfcmVjb3ZlcmVkX3NlcmllcykKYGBgCgpgYGB7cn0KZHlncmFwaChEYXlfc3VtbWFyeSwgbWFpbiA9ICJTQVJTLUNPVjItb3V0YnJlYWs6IFRvdGFsIHdvcmxkd2lkZSBjYXNlcyIsIAogICAgICAgIHhsYWI9IkRhdGUiLCB5bGFiPSJUb3RhbCBjYXNlcyIsd2lkdGggPSA3NTApICU+JSAKICBkeVNlcmllcygiQ09WSURfRGF5X2NvbmZpcm1lZF9zZXJpZXMiLCAiVG90YWwgY2FzZXMiLGRyYXdQb2ludHMgPSBUUlVFLCAKICAgICAgICAgICBwb2ludFNpemUgPSAzLCBjb2xvcj1yZ2IoNTMvMjU1LDExNi8yNTUsMTk5LzI1NSkpICU+JSAKICBkeVNlcmllcygiQ09WSURfRGF5X2RlYXRoc19zZXJpZXMiLCAiVG90YWwgZGVhdGhzIixkcmF3UG9pbnRzID0gVFJVRSwgCiAgICAgICAgICAgcG9pbnRTaXplID0gMywgY29sb3I9cmdiKDE4OS8yNTUsNTUvMjU1LDQ4LzI1NSkpICU+JSAKICBkeVNlcmllcygiQ09WSURfRGF5X3JlY292ZXJlZF9zZXJpZXMiLCAiVG90YWwgcmVjb3ZlcmVkIixkcmF3UG9pbnRzID0gVFJVRSwgCiAgICAgICAgICAgcG9pbnRTaXplID0gMywgY29sb3I9cmdiKDY5LzI1NSwxMzYvMjU1LDUxLzI1NSkpICU+JSAKICBkeVJhbmdlU2VsZWN0b3IoKQpgYGAKCgpgYGB7cn0KTmV3X2NvdW50PC1mdW5jdGlvbih4KQp7CiAgRGFpbHlfY2FzZXM8LW51bWVyaWMobGVuZ3RoKHgpKQogIAogIGZvcihpIGluIGxlbmd0aCh4KToyKQogIHsKICAgIERhaWx5X2Nhc2VzW2ldPXhbaV0gLSB4W2ktMV0KICB9CiAgcmV0dXJuKERhaWx5X2Nhc2VzKQp9CgpOZXdfY2FzZXM8LU5ld19jb3VudChDT1ZJRF8yX0RheSRXb3JsZF9jb25maXJtZWQpCk5ld19kZWF0aHM8LU5ld19jb3VudChDT1ZJRF8yX0RheSRXb3JsZF9kZWF0aHMpCk5ld19yZWNvdmVyZWQ8LU5ld19jb3VudChDT1ZJRF8yX0RheSRXb3JsZF9yZWNvdmVyZWQpCkNPVklEX05ld19jb25maXJtZWRfc2VyaWVzPC14dHMoTmV3X2Nhc2VzLCBvcmRlci5ieT1DT1ZJRF8yX0RheSREYXRlMikKQ09WSURfTmV3X2RlYXRoc19zZXJpZXM8LXh0cyhOZXdfZGVhdGhzLCBvcmRlci5ieT1DT1ZJRF8yX0RheSREYXRlMikKQ09WSURfTmV3X3JlY292ZXJlZF9zZXJpZXM8LXh0cyhOZXdfcmVjb3ZlcmVkLCBvcmRlci5ieT1DT1ZJRF8yX0RheSREYXRlMikKCk5ld19zdW1tYXJ5PC1jYmluZChDT1ZJRF9OZXdfY29uZmlybWVkX3NlcmllcyxDT1ZJRF9OZXdfZGVhdGhzX3NlcmllcyxDT1ZJRF9OZXdfcmVjb3ZlcmVkX3NlcmllcykKYGBgCgpgYGB7cn0KZHlncmFwaChOZXdfc3VtbWFyeSwgbWFpbiA9ICJTQVJTLUNPVjItb3V0YnJlYWs6IFRvdGFsIHdvcmxkd2lkZSBjYXNlcyIsIAogICAgICAgIHhsYWI9IkRhdGUiLCB5bGFiPSJOb3ZlbCBjb3JvbmF2aXJ1cyBjYXNlcyIsd2lkdGggPSA3NTApICU+JSAKICBkeVNlcmllcygiQ09WSURfTmV3X2NvbmZpcm1lZF9zZXJpZXMiLCAiTmV3IGNhc2VzIixkcmF3UG9pbnRzID0gVFJVRSwgCiAgICAgICAgICAgcG9pbnRTaXplID0gMywgY29sb3I9cmdiKDUzLzI1NSwxMTYvMjU1LDE5OS8yNTUpKSAlPiUgCiAgZHlTZXJpZXMoIkNPVklEX05ld19kZWF0aHNfc2VyaWVzIiwgIk5ldyBkZWF0aHMiLGRyYXdQb2ludHMgPSBUUlVFLCAKICAgICAgICAgICBwb2ludFNpemUgPSAzLCBjb2xvcj1yZ2IoMTg5LzI1NSw1NS8yNTUsNDgvMjU1KSkgJT4lIAogIGR5U2VyaWVzKCJDT1ZJRF9OZXdfcmVjb3ZlcmVkX3NlcmllcyIsICJOZXcgcmVjb3ZlcmVkIixkcmF3UG9pbnRzID0gVFJVRSwgCiAgICAgICAgICAgcG9pbnRTaXplID0gMywgY29sb3I9cmdiKDY5LzI1NSwxMzYvMjU1LDUxLzI1NSkpICU+JSAKICBkeVJhbmdlU2VsZWN0b3IoKQpgYGAKCgpUZWFtIG1lbWJlcnMgY291bnRyaWVzIHRvdGFsIGNhc2VzOgpgYGB7cn0KQ09WSURfMl9EYXlfTGViYW5vbjwtIENPVklEXzIgJT4lIAogIGZpbHRlcihDb3VudHJ5LlJlZ2lvbiAlaW4lIGMoIkxlYmFub24iKSkgJT4lIAogIGdyb3VwX2J5KERhdGUyKSAlPiUgc3VtbWFyaXNlKFdvcmxkX2NvbmZpcm1lZD1zdW0oQ29uZmlybWVkKSkKCkNPVklEXzJfRGF5X0NoaWxlPC0gQ09WSURfMiAlPiUgCiAgZmlsdGVyKENvdW50cnkuUmVnaW9uICVpbiUgYygiQ2hpbGUiKSkgJT4lIAogIGdyb3VwX2J5KERhdGUyKSAlPiUgc3VtbWFyaXNlKFdvcmxkX2NvbmZpcm1lZD1zdW0oQ29uZmlybWVkKSkKCkNPVklEXzJfRGF5X0NvbG9tYmlhPC0gQ09WSURfMiAlPiUgCiAgZmlsdGVyKENvdW50cnkuUmVnaW9uICVpbiUgYygiQ29sb21iaWEiKSkgJT4lIAogIGdyb3VwX2J5KERhdGUyKSAlPiUgc3VtbWFyaXNlKFdvcmxkX2NvbmZpcm1lZD1zdW0oQ29uZmlybWVkKSkKCkNPVklEXzJfRGF5X0Nvc3RhUmljYTwtIENPVklEXzIgJT4lIAogIGZpbHRlcihDb3VudHJ5LlJlZ2lvbiAlaW4lIGMoIkNvc3RhIFJpY2EiKSkgJT4lIAogIGdyb3VwX2J5KERhdGUyKSAlPiUgc3VtbWFyaXNlKFdvcmxkX2NvbmZpcm1lZD1zdW0oQ29uZmlybWVkKSkKCgpDT1ZJRF9EYXlfc2VyaWVzX0xlYmFub248LXh0cyhDT1ZJRF8yX0RheV9MZWJhbm9uJFdvcmxkX2NvbmZpcm1lZCwgb3JkZXIuYnk9Q09WSURfMl9EYXlfTGViYW5vbiREYXRlMikKQ09WSURfRGF5X3Nlcmllc19DaGlsZTwteHRzKENPVklEXzJfRGF5X0NoaWxlJFdvcmxkX2NvbmZpcm1lZCwgb3JkZXIuYnk9Q09WSURfMl9EYXlfQ2hpbGUkRGF0ZTIpCkNPVklEX0RheV9zZXJpZXNfQ29sb21iaWE8LXh0cyhDT1ZJRF8yX0RheV9Db2xvbWJpYSRXb3JsZF9jb25maXJtZWQsIG9yZGVyLmJ5PUNPVklEXzJfRGF5X0NvbG9tYmlhJERhdGUyKQpDT1ZJRF9EYXlfc2VyaWVzX0Nvc3RhUmljYTwteHRzKENPVklEXzJfRGF5X0Nvc3RhUmljYSRXb3JsZF9jb25maXJtZWQsIG9yZGVyLmJ5PUNPVklEXzJfRGF5X0Nvc3RhUmljYSREYXRlMikKCk91cl9Db3VudHJpZXM8LWNiaW5kKENPVklEX0RheV9zZXJpZXNfTGViYW5vbixDT1ZJRF9EYXlfc2VyaWVzX0NoaWxlLENPVklEX0RheV9zZXJpZXNfQ29sb21iaWEsQ09WSURfRGF5X3Nlcmllc19Db3N0YVJpY2EpCgpgYGAKCmBgYHtyfQpkeWdyYXBoKE91cl9Db3VudHJpZXMsIG1haW4gPSAiU0FSUy1DT1YyLW91dGJyZWFrOiBUb3RhbCBjYXNlcyBieSBjb3VudHJ5IiwgeGxhYj0iRGF0ZSIsIHlsYWI9IlRvdGFsIGNhc2VzIix3aWR0aCA9IDc1MCkgJT4lIAogIGR5U2VyaWVzKCJDT1ZJRF9EYXlfc2VyaWVzX0xlYmFub24iLCAiTGViYW5vbiIsZHJhd1BvaW50cyA9IFRSVUUsIAogICAgICAgICAgIHBvaW50U2l6ZSA9IDMsIGNvbG9yPXJnYigwLDAsMy8yNTUpKSAlPiUgCiAgZHlTZXJpZXMoIkNPVklEX0RheV9zZXJpZXNfQ2hpbGUiLCAiQ2hpbGUiLGRyYXdQb2ludHMgPSBUUlVFLCAKICAgICAgICAgICBwb2ludFNpemUgPSAzLGNvbG9yPXJnYigxMjAvMjU1LDI4LzI1NSwxMDkvMjU1KSkgJT4lIAogIGR5U2VyaWVzKCJDT1ZJRF9EYXlfc2VyaWVzX0NvbG9tYmlhIiwgIkNvbG9tYmlhIixkcmF3UG9pbnRzID0gVFJVRSwgCiAgICAgICAgICAgcG9pbnRTaXplID0gMyxjb2xvcj1yZ2IoMjM3LzI1NSwxMDUvMjU1LDM3LzI1NSkpICU+JSAKICBkeVNlcmllcygiQ09WSURfRGF5X3Nlcmllc19Db3N0YVJpY2EiLCAiQ29zdGEgUmljYSIsZHJhd1BvaW50cyA9IFRSVUUsCiAgICAgICAgICAgcG9pbnRTaXplID0gMyxjb2xvcj1yZ2IoMjA0LzI1NSwxOTcvMjU1LDEyNi8yNTUpKSAlPiUgCiAgZHlSYW5nZVNlbGVjdG9yKCkKYGBgCgpgYGB7cn0KTmV3X0xlYmFub248LU5ld19jb3VudChDT1ZJRF8yX0RheV9MZWJhbm9uJFdvcmxkX2NvbmZpcm1lZCkKTmV3X0NoaWxlPC1OZXdfY291bnQoQ09WSURfMl9EYXlfQ2hpbGUkV29ybGRfY29uZmlybWVkKQpOZXdfQ29sb21iaWE8LU5ld19jb3VudChDT1ZJRF8yX0RheV9Db2xvbWJpYSRXb3JsZF9jb25maXJtZWQpCk5ld19Db3N0YVJpY2E8LU5ld19jb3VudChDT1ZJRF8yX0RheV9Db3N0YVJpY2EkV29ybGRfY29uZmlybWVkKQoKQ09WSURfTmV3X3Nlcmllc19MZWJhbm9uPC14dHMoTmV3X0xlYmFub24sIG9yZGVyLmJ5PUNPVklEXzJfRGF5X0xlYmFub24kRGF0ZTIpCkNPVklEX05ld19zZXJpZXNfQ2hpbGU8LXh0cyhOZXdfQ2hpbGUsIG9yZGVyLmJ5PUNPVklEXzJfRGF5X0NoaWxlJERhdGUyKQpDT1ZJRF9OZXdfc2VyaWVzX0NvbG9tYmlhPC14dHMoTmV3X0NvbG9tYmlhLCBvcmRlci5ieT1DT1ZJRF8yX0RheV9Db2xvbWJpYSREYXRlMikKQ09WSURfTmV3X3Nlcmllc19Db3N0YVJpY2E8LXh0cyhOZXdfQ29zdGFSaWNhLCBvcmRlci5ieT1DT1ZJRF8yX0RheV9Db3N0YVJpY2EkRGF0ZTIpCgpPdXJfTmV3X0NvdW50cmllczwtY2JpbmQoQ09WSURfTmV3X3Nlcmllc19MZWJhbm9uLENPVklEX05ld19zZXJpZXNfQ2hpbGUsQ09WSURfTmV3X3Nlcmllc19Db2xvbWJpYSxDT1ZJRF9OZXdfc2VyaWVzX0Nvc3RhUmljYSkKYGBgCgpgYGB7cn0KZHlncmFwaChPdXJfTmV3X0NvdW50cmllcywgbWFpbiA9ICJTQVJTLUNPVjItb3V0YnJlYWs6IE5ldyBjYXNlcyBieSBjb3VudHJ5IiwgeGxhYj0iRGF0ZSIsIHlsYWI9IlRvdGFsIGNhc2VzIix3aWR0aCA9IDc1MCkgJT4lIAogIGR5U2VyaWVzKCJDT1ZJRF9OZXdfc2VyaWVzX0xlYmFub24iLCAiTGViYW5vbiIsZHJhd1BvaW50cyA9IFRSVUUsIAogICAgICAgICAgIHBvaW50U2l6ZSA9IDMsIGNvbG9yPXJnYigwLDAsMy8yNTUpKSAlPiUgCiAgZHlTZXJpZXMoIkNPVklEX05ld19zZXJpZXNfQ2hpbGUiLCAiQ2hpbGUiLGRyYXdQb2ludHMgPSBUUlVFLCAKICAgICAgICAgICBwb2ludFNpemUgPSAzLGNvbG9yPXJnYigxMjAvMjU1LDI4LzI1NSwxMDkvMjU1KSkgJT4lIAogIGR5U2VyaWVzKCJDT1ZJRF9OZXdfc2VyaWVzX0NvbG9tYmlhIiwgIkNvbG9tYmlhIixkcmF3UG9pbnRzID0gVFJVRSwgCiAgICAgICAgICAgcG9pbnRTaXplID0gMyxjb2xvcj1yZ2IoMjM3LzI1NSwxMDUvMjU1LDM3LzI1NSkpICU+JSAKICBkeVNlcmllcygiQ09WSURfTmV3X3Nlcmllc19Db3N0YVJpY2EiLCAiQ29zdGEgUmljYSIsZHJhd1BvaW50cyA9IFRSVUUsCiAgICAgICAgICAgcG9pbnRTaXplID0gMyxjb2xvcj1yZ2IoMjA0LzI1NSwxOTcvMjU1LDEyNi8yNTUpKSAlPiUgCiAgZHlSYW5nZVNlbGVjdG9yKCkKYGBgCgojIExvb2tpbmcgZm9yIGNvcnJlbGF0aW9ucwoKYGBge3J9CmZpZyA8LSBwbG90X2x5KENPVklEX3VwZGF0ZWQsIHggPSB+Q29uZmlybWVkLCB5ID0gfkRlYXRocywgeiA9IH5SZWNvdmVyZWQsIHdpZHRoPTc1MCkgJT4lIAogIGFkZF9tYXJrZXJzKHRleHQ9IH5Db3VudHJ5LlJlZ2lvbiAsaG92ZXJpbmZvPSAidGV4dCIsCiAgICAgICAgICAgICAgbWFya2VyID0gbGlzdChjb2xvcj1yZ2IoMTg5LzI1NSw1NS8yNTUsNDgvMjU1KSkpICU+JSAKICBsYXlvdXQodGl0bGU9IkNvbmZpcm1lZCBjYXNlcyBWcy4gRGVhdGhzIFZzLiBSZWNvdmVyZWQiLCBzY2VuZSA9IGxpc3QoCiAgICAgICAgICAgICAgICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gJ0NvbmZpcm1lZCcpLAogICAgICAgICAgICAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAnRGVhdGhzJyksCiAgICAgICAgICAgICAgICAgICAgIHpheGlzID0gbGlzdCh0aXRsZSA9ICdSZWNvdmVyZWQnKSkpIApmaWcKYGBgCiMjIEZvciB0aGUgbnVtYmVyIG9mIGNhc2VzCgojIyMgSHVtYW4gRGV2ZWxvcG1lbnQgSW5kZXgKCmBgYHtyfQpIREk8LXJlYWQuY3N2KCJIdW1hbiBEZXZlbG9wbWVudCBJbmRleCAoSERJKV8yLmNzdiIsc2VwPSI7IixkZWM9IiwiKQpgYGAKCmBgYHtyfQpDT1ZJRF9Db3VudHJ5PC1DT1ZJRF8yICU+JSBmaWx0ZXIoRGF0ZTI9PW1heChEYXRlMikpICU+JSAKICBncm91cF9ieShDb3VudHJ5LlJlZ2lvbikgJT4lIHN1bW1hcmlzZShUb3RhbF9jb25maXJtZWQ9c3VtKENvbmZpcm1lZCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVG90YWxfZGVhdGhzPXN1bShEZWF0aHMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRvdGFsX1JlY292ZXJlZD1zdW0oUmVjb3ZlcmVkKSkKYGBgCgpSZW1vdmUgYWZ0ZXIgcGFyZW50aGVzZXM6CmBgYHtyfQpIREkkQ291bnRyeV8yPC1nc3ViKCJcXHMqXFwoW15cXCldK1xcKSIsIiIsYXMuY2hhcmFjdGVyKEhESSRDb3VudHJ5KSkKYGBgCgpgYGB7cn0KSERJJENvdW50cnlfMltIREkkQ291bnRyeV8yPT0iVW5pdGVkIFN0YXRlcyJdPC0iVVMiCkhESSRDb3VudHJ5XzJbSERJJENvdW50cnlfMj09IktvcmVhIl08LSJTb3V0aCBLb3JlYSIKYGBgCgpQb3B1bGF0aW9uOgpgYGB7cn0KUG9wdWxhdGlvbjwtcmVhZC5jc3YoIldvcmxkX3BvcHVsYXRpb24uY3N2IixzZXA9IjsiLGRlYz0iLCIpCmBgYAoKUmVtb3ZlIGFmdGVyIGNvbW1tYToKYGBge3J9ClBvcHVsYXRpb24kQ291bnRyeV9OYW1lXzI8LWdzdWIoIiwuKiIsICIiLCBhcy5jaGFyYWN0ZXIoUG9wdWxhdGlvbiRDb3VudHJ5X05hbWUpKQpgYGAKCmBgYHtyfQpQb3B1bGF0aW9uJENvdW50cnlfTmFtZV8yW1BvcHVsYXRpb24kQ291bnRyeV9OYW1lXzI9PSJVbml0ZWQgU3RhdGVzIl08LSJVUyIKUG9wdWxhdGlvbiRDb3VudHJ5X05hbWVfMltQb3B1bGF0aW9uJENvdW50cnlfQ29kZT09IktPUiJdPC0iU291dGggS29yZWEiClBvcHVsYXRpb24kQ291bnRyeV9OYW1lXzJbUG9wdWxhdGlvbiRDb3VudHJ5X0NvZGU9PSJDWkUiXTwtIkN6ZWNoaWEiCmBgYAoKTmF0dXJhbCBKb2luOgpgYGB7cix3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0V9CkNPVklEXzM8LSBDT1ZJRF9Db3VudHJ5ICU+JSBpbm5lcl9qb2luKEhESSxieT1jKCJDb3VudHJ5LlJlZ2lvbiI9IkNvdW50cnlfMiIpKSAlPiUgCiAgaW5uZXJfam9pbihQb3B1bGF0aW9uLGJ5PWMoIkNvdW50cnkuUmVnaW9uIj0iQ291bnRyeV9OYW1lXzIiKSkgJT4lIAogIHNlbGVjdChDb3VudHJ5LlJlZ2lvbixUb3RhbF9jb25maXJtZWQsVG90YWxfZGVhdGhzLFRvdGFsX1JlY292ZXJlZCxIRElfUmFua18yMDE4LFllYXJfMjAxOCwKICAgICAgICAgQ291bnRyeV9Db2RlLFBvcHVsYXRpb25fMjAxOCkgJT4lIAogIG11dGF0ZShDYXNlc19taWxsaW9uPShUb3RhbF9jb25maXJtZWQvUG9wdWxhdGlvbl8yMDE4KSoxMDAwMDAwLAogICAgICAgICBSZWNvdmVyZWRfcGVyY2VudGFnZT0oVG90YWxfUmVjb3ZlcmVkL1RvdGFsX2NvbmZpcm1lZCkqMTAwKSAgCgpDT1ZJRF8zPC1DT1ZJRF8zWyFpcy5uYShDT1ZJRF8zJFBvcHVsYXRpb25fMjAxOCksXQoKYGBgCgpQbG90IHRoZSBIdW1hbiBEZXZlbG9wbWVudCBJbmRleChIREkpIFZzLiB0aGUgbnVtYmVyIG9mIGNhc2VzIChhcHBseWluZyBhIGxvZyB0cmFuc2Zvcm1hdGlvbiksIGFuZCB0aGUgcHJvcG9ydGlvbiBvZiByZWNvdmVyZWQgY2FzZXM6CmBgYHtyfQpwbG90PC1nZ3Bsb3QoZGF0YT1DT1ZJRF8zLGFlcyh4PWxvZyhDYXNlc19taWxsaW9uKSx5PVllYXJfMjAxOCwKICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZT1SZWNvdmVyZWRfcGVyY2VudGFnZSx0ZXh0PUNvdW50cnkuUmVnaW9uKSkgKwogIGdlb21fcG9pbnQoY29sb3I9ImJsYWNrIixmaWxsPXJnYigyMzcvMjU1LDEwNS8yNTUsMzcvMjU1KSxzaGFwZT0yMSxhbHBoYT0wLjYpICsKICBzY2FsZV9zaXplKHJhbmdlID0gYygzLDE1KSwgbmFtZT0iUmVjb3ZlcmVkIFxuIHBlcmNlbnRhZ2UiKSArCiAgdGhlbWVfbWluaW1hbCgpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iKSArCiAgbGFicyh0aXRsZT0iSERJIFZzLiBsb2dhcml0aG11cyBvZiBDT1ZJRC0xOSBjYXNlcyBieSBtaWxsaW9uIGluaGFiaXRhbnRzIFxuIGFuZCBwcm9wb3J0aW9uIG9mIHJlY292ZXJlZCIsCiAgICAgICB4PSJsbihDYXNlcy8xTSBwb3B1bGF0aW9uKSIsCiAgICAgICB5PSJIREkiKQoKZ2dwbG90bHkocGxvdCx0b29sdGlwID0gYygidGV4dCIpLHdpZHRoPTc1MCkKYGBgCgoKYGBge3J9CkNPVklEX251bWVyaWNfMTwtQ09WSURfMyAlPiUgbXV0YXRlKExvZ19jYXNlcz1sb2coQ2FzZXNfbWlsbGlvbiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERlYXRoX3BlcmNlbnRhZ2U9KFRvdGFsX2RlYXRocy9Ub3RhbF9jb25maXJtZWQpKjEwMCkgJT4lIAogIHNlbGVjdChMb2dfY2FzZXMsUmVjb3ZlcmVkX3BlcmNlbnRhZ2UsRGVhdGhfcGVyY2VudGFnZSxZZWFyXzIwMTgpCgpjb3JycGxvdChjb3IoQ09WSURfbnVtZXJpY18xKSxtZXRob2QgPSAibnVtYmVyIix0bC5jb2w9ImJsYWNrIix0bC5zcnQ9MTUsCiAgICAgICAgIGNvbD1jb2xvclJhbXBQYWxldHRlKGMocmdiKDIwNC8yNTUsMTk3LzI1NSwxMjYvMjU1KSxyZ2IoMjM3LzI1NSwxMDUvMjU1LDM3LzI1NSkpKSgyMDApKQpgYGAKCiMjIyBIZWFsdGggZXhwZW5kaXR1cmUgKCUgb2YgR0RQKQoKYGBge3J9CkhlYWx0aF9leHBlbmRpdHVyZTwtcmVhZC5jc3YoIkhlYWx0aF9leHBlbmRpdHVyZV9HRFAuY3N2IixzZXA9IjsiLGRlYz0iLiIpCmBgYAoKYGBge3J9CkhlYWx0aF9leHBlbmRpdHVyZSRDb3VudHJ5XzI8LWdzdWIoIlxccypcXChbXlxcKV0rXFwpIiwiIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcy5jaGFyYWN0ZXIoSGVhbHRoX2V4cGVuZGl0dXJlJENvdW50cnkpKQpgYGAKCmBgYHtyfQpIZWFsdGhfZXhwZW5kaXR1cmUkQ291bnRyeV8yW0hlYWx0aF9leHBlbmRpdHVyZSRDb3VudHJ5XzI9PSJVbml0ZWQgU3RhdGVzIl08LSJVUyIKSGVhbHRoX2V4cGVuZGl0dXJlJENvdW50cnlfMltIZWFsdGhfZXhwZW5kaXR1cmUkQ291bnRyeV8yPT0iS29yZWEiXTwtIlNvdXRoIEtvcmVhIgpgYGAKCgpgYGB7cn0KQ09WSURfMzwtIENPVklEXzMgJT4lIGlubmVyX2pvaW4oSGVhbHRoX2V4cGVuZGl0dXJlLGJ5PWMoIkNvdW50cnkuUmVnaW9uIj0iQ291bnRyeV8yIikpICU+JSBzZWxlY3QoLWMoIkNvdW50cnkiKSkKYGBgCgpgYGB7cn0KcGxvdDwtZ2dwbG90KGRhdGE9Q09WSURfMyxhZXMoeD1sb2coQ2FzZXNfbWlsbGlvbikseT1FeHBlbmRpdHVyZV8yMDE2LAogICAgICAgICAgICAgICAgICAgICAgICBzaXplPVJlY292ZXJlZF9wZXJjZW50YWdlLHRleHQ9Q291bnRyeS5SZWdpb24pKSArCiAgZ2VvbV9wb2ludChjb2xvcj0iYmxhY2siLGZpbGw9cmdiKDIwNC8yNTUsMTk3LzI1NSwxMjYvMjU1KSxzaGFwZT0yMSxhbHBoYT0wLjYpICsKICBzY2FsZV9zaXplKHJhbmdlID0gYygzLDE1KSwgbmFtZT0iUmVjb3ZlcmVkIFxuIHBlcmNlbnRhZ2UiKSArCiAgdGhlbWVfbWluaW1hbCgpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iKSArCiAgbGFicyh0aXRsZT0iSGVhbHRoIGV4cGVuZGl0dXJlICglIG9mIEdEUCkgVnMuIGxvZ2FyaXRobXVzIG9mIENPVklELTE5IGNhc2VzIGJ5IG1pbGxpb24gaW5oYWJpdGFudHMgXG4gYW5kIHByb3BvcnRpb24gb2YgcmVjb3ZlcmVkIiwKICAgICAgIHg9ImxuKENhc2VzLzFNIHBvcHVsYXRpb24pIiwKICAgICAgIHk9IiUgb2YgR0RQIGluIGhlYWx0aCIpCgpnZ3Bsb3RseShwbG90LHRvb2x0aXAgPSBjKCJ0ZXh0Iiksd2lkdGg9NzUwKQpgYGAKCiMjIyBUZW1wZXJhdHVyZQoKYGBge3J9ClRlbXBlcmF0dXJlPC1yZWFkLmNzdigiR2xvYmFsTGFuZFRlbXBlcmF0dXJlc0J5Q291bnRyeS5jc3YiLHNlcD0iOyIpCmBgYAoKYGBge3J9CkRhdGVfVGVtcDwtYXMuRGF0ZShUZW1wZXJhdHVyZSRkdCwgZm9ybWF0PSIlZC8lbS8lWSIpIAoKVGVtcGVyYXR1cmUkRGF0ZV9UZW1wPC1EYXRlX1RlbXAKYGBgCgpFeHRyYWN0IG1vbnRoLCBmaWx0ZXIgSVEgKEphbiwgRmViIGFuZCBNYXIpIGFuZCBvYnRhaW4gdGhlIGF2ZXJhZ2UgSVEgdGVtcGVyYXR1cmU6CmBgYHtyfQpUZW1wZXJhdHVyZTwtIFRlbXBlcmF0dXJlICU+JSBtdXRhdGUoTW9udGg9bW9udGgoVGVtcGVyYXR1cmUkRGF0ZV9UZW1wLGxhYmVsID1UUlVFKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFllYXI9eWVhcihUZW1wZXJhdHVyZSREYXRlX1RlbXApKSAlPiUgCiAgZmlsdGVyKE1vbnRoICVpbiUgYygiSmFuIiwiRmViIiwiTWFyIikgJiBZZWFyPj0yMDAwKSAgJT4lIAogIGdyb3VwX2J5KENvdW50cnkpICU+JSBzdW1tYXJpc2UoQXZnX0lRX3RlbXBlcmF0dXJlPW1lYW4oQXZlcmFnZVRlbXBlcmF0dXJlKSkKClRlbXBlcmF0dXJlPC1UZW1wZXJhdHVyZVshaXMubmEoVGVtcGVyYXR1cmUkQXZnX0lRX3RlbXBlcmF0dXJlKSxdCmBgYAoKYGBge3J9ClRlbXBlcmF0dXJlJENvdW50cnlfMjwtZ3N1YigiXFxzKlxcKFteXFwpXStcXCkiLCIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzLmNoYXJhY3RlcihUZW1wZXJhdHVyZSRDb3VudHJ5KSkKYGBgCgpgYGB7cn0KVGVtcGVyYXR1cmUkQ291bnRyeV8yW1RlbXBlcmF0dXJlJENvdW50cnlfMj09IlVuaXRlZCBTdGF0ZXMiXTwtIlVTIgpUZW1wZXJhdHVyZSRDb3VudHJ5XzJbVGVtcGVyYXR1cmUkQ291bnRyeV8yPT0iS29yZWEiXTwtIlNvdXRoIEtvcmVhIgpgYGAKCmBgYHtyfQpDT1ZJRF8zPC0gQ09WSURfMyAlPiUgaW5uZXJfam9pbihUZW1wZXJhdHVyZSxieT1jKCJDb3VudHJ5LlJlZ2lvbiI9IkNvdW50cnlfMiIpKSAlPiUgc2VsZWN0KC1jKCJDb3VudHJ5IikpCgojd3JpdGUuY3N2KENPVklEXzMsIkNPVklEX0NvdmFyaWFibGVzLmNzdiIpCmBgYAoKYGBge3J9CnBsb3Q8LWdncGxvdChkYXRhPUNPVklEXzMsYWVzKHg9bG9nKENhc2VzX21pbGxpb24pLHk9QXZnX0lRX3RlbXBlcmF0dXJlLAogICAgICAgICAgICAgICAgICAgICAgICBzaXplPVJlY292ZXJlZF9wZXJjZW50YWdlLHRleHQ9Q291bnRyeS5SZWdpb24pKSArCiAgZ2VvbV9wb2ludChjb2xvcj0iYmxhY2siLGZpbGw9cmdiKDEyMC8yNTUsMjgvMjU1LDEwOS8yNTUpLHNoYXBlPTIxLGFscGhhPTAuNikgKwogIHNjYWxlX3NpemUocmFuZ2UgPSBjKDMsMTUpLCBuYW1lPSJSZWNvdmVyZWQgXG4gcGVyY2VudGFnZSIpICsKICB0aGVtZV9taW5pbWFsKCkgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIpICsKICBsYWJzKHRpdGxlPSJBdmVyYWdlIElRIHRlbXBlcmF0dXJlIFZzLiBsb2dhcml0aG11cyBvZiBDT1ZJRC0xOSBjYXNlcyBieSBtaWxsaW9uIGluaGFiaXRhbnRzIFxuIGFuZCBwcm9wb3J0aW9uIG9mIHJlY292ZXJlZCIsCiAgICAgICB4PSJsbihDYXNlcy8xTSBwb3B1bGF0aW9uKSIsCiAgICAgICB5PSJUZW1wZXJhdHVyZSAoQ2VsY2l1cykiKQoKZ2dwbG90bHkocGxvdCx0b29sdGlwID0gYygidGV4dCIpLHdpZHRoPTc1MCkKYGBgCgojIyBGb3IgdGhlIG51bWJlciBvZiBkZWF0aHMKCiMjI0RUUCBpbW11bml6YXRpb24KCmBgYHtyfQpEVFBfaW1tdW5pemF0aW9uPC1yZWFkLmNzdigiSW5mYW50c19sYWNraW5nX2ltbXVuaXphdGlvbl9EVFAuY3N2IixzZXA9IjsiKQpgYGAKClJlbW92ZSBhZnRlciBwYXJlbnRoZXNlczoKYGBge3J9CkRUUF9pbW11bml6YXRpb24kQ291bnRyeV8yPC1nc3ViKCJcXHMqXFwoW15cXCldK1xcKSIsIiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzLmNoYXJhY3RlcihEVFBfaW1tdW5pemF0aW9uJENvdW50cnkpKQpgYGAKCgpgYGB7cn0KRFRQX2ltbXVuaXphdGlvbiRDb3VudHJ5XzJbRFRQX2ltbXVuaXphdGlvbiRDb3VudHJ5XzI9PSJVbml0ZWQgU3RhdGVzIl08LSJVUyIKRFRQX2ltbXVuaXphdGlvbiRDb3VudHJ5XzJbRFRQX2ltbXVuaXphdGlvbiRDb3VudHJ5XzI9PSJLb3JlYSJdPC0iU291dGggS29yZWEiCmBgYAoKCmBgYHtyLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0KQ09WSURfNDwtIENPVklEX0NvdW50cnkgJT4lIGlubmVyX2pvaW4oRFRQX2ltbXVuaXphdGlvbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnk9YygiQ291bnRyeS5SZWdpb24iPSJDb3VudHJ5XzIiKSkgJT4lIAogIHNlbGVjdChDb3VudHJ5LlJlZ2lvbixUb3RhbF9jb25maXJtZWQsVG90YWxfZGVhdGhzLFRvdGFsX1JlY292ZXJlZCwKICAgICAgICAgTGFja19EVFBfaW5tbXVuaXphdGlvbl8yMDE4KSAlPiUgCiAgbXV0YXRlKFJlY292ZXJlZF9wZXJjZW50YWdlPShUb3RhbF9SZWNvdmVyZWQvVG90YWxfY29uZmlybWVkKSoxMDAsCiAgICAgICAgIERlYXRoX3JhdGU9KFRvdGFsX2RlYXRocy9Ub3RhbF9jb25maXJtZWQpKjEwMCkKYGBgCgpgYGB7cn0KcGxvdDwtZ2dwbG90KGRhdGE9Q09WSURfNCxhZXMoeD1EZWF0aF9yYXRlLHk9TGFja19EVFBfaW5tbXVuaXphdGlvbl8yMDE4LAogICAgICAgICAgICAgICAgICAgICAgICBzaXplPVJlY292ZXJlZF9wZXJjZW50YWdlLHRleHQ9Q291bnRyeS5SZWdpb24pKSArCiAgZ2VvbV9wb2ludChjb2xvcj0iYmxhY2siLGZpbGw9cmdiKDEyMC8yNTUsMjgvMjU1LDEwOS8yNTUpLHNoYXBlPTIxLGFscGhhPTAuNikgKwogIHNjYWxlX3NpemUocmFuZ2UgPSBjKDMsMTUpLCBuYW1lPSJSZWNvdmVyZWQgXG4gcGVyY2VudGFnZSIpICsKICB0aGVtZV9taW5pbWFsKCkgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIpICsKICBsYWJzKHRpdGxlPSIlIGluZmFudHMgbGFja2luZyBEVFAgaW1tdW5pemF0aW9uIFZzLiBkZWF0aCByYXRlIGFuZCBcbiBwcm9wb3J0aW9uIG9mIHJlY292ZXJlZCIsCiAgICAgICB4PSJOb3ZlbCBjb3JvbmF2aXJ1cyBkZWF0aCByYXRlIiwKICAgICAgIHk9IiUgb2YgaW5mYW50cyIpCgpnZ3Bsb3RseShwbG90LHRvb2x0aXAgPSBjKCJ0ZXh0Iiksd2lkdGg9NzUwKQpgYGAKCiMjIyBJbmZhbnRzIGxhY2tpbmcgaW1tdW5pemF0aW9uLCBtZWFzbGVzICglIG9mIG9uZS15ZWFyLW9sZHMpCgpgYGB7cn0KTWVhc2xlczwtcmVhZC5jc3YoIk1lYXNsZXNfaW1tdW5pemF0aW9uLmNzdiIsc2VwPSI7IixkZWM9Ii4iKQpgYGAKCmBgYHtyfQpNZWFzbGVzJENvdW50cnlfMjwtZ3N1YigiXFxzKlxcKFteXFwpXStcXCkiLCIiLGFzLmNoYXJhY3RlcihNZWFzbGVzJENvdW50cnkpKQpgYGAKCmBgYHtyfQpNZWFzbGVzJENvdW50cnlfMltNZWFzbGVzJENvdW50cnlfMj09IlVuaXRlZCBTdGF0ZXMiXTwtIlVTIgpNZWFzbGVzJENvdW50cnlfMltNZWFzbGVzJENvdW50cnlfMj09IktvcmVhIl08LSJTb3V0aCBLb3JlYSIKYGBgCgoKYGBge3J9CkNPVklEXzQ8LSBDT1ZJRF80ICU+JSBpbm5lcl9qb2luKE1lYXNsZXMsYnk9YygiQ291bnRyeS5SZWdpb24iPSJDb3VudHJ5XzIiKSkgJT4lIHNlbGVjdCgtYygiQ291bnRyeSIpKQpgYGAKCgpgYGB7cn0KZ2dwbG90KENPVklEXzQsIGFlcyh5PU1lYXNsZXNfMjAxOCkpICsgCiAgZ2VvbV9ib3hwbG90KGZpbGw9ImRvZGdlcmJsdWU0IixvdXRsaWVyLnNoYXBlID0gMjEsIAogICAgICAgICAgICAgICBvdXRsaWVyLmZpbGwgPSAiZmlyZWJyaWNrIixhbHBoYT0wLjc1KSArCiAgZ2d0aXRsZSgiQm94cGxvdCBvZiAlIGluZmFudHMgbGFja2luZyBtZWFzbGVzIGltbXVuaXphdGlvbiIpICsgeWxhYigiJSBvZiBpbmZhbnRzIikgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKCmBgYHtyfQpnZ3Bsb3QoQ09WSURfNCwgYWVzKE1lYXNsZXNfMjAxOCkpICsgCiAgZ2VvbV9oaXN0b2dyYW0oZmlsbD0iZG9kZ2VyYmx1ZTQiLGJpbnM9MjAsYWxwaGE9MC44KSArCiAgZ2d0aXRsZSgiSGlzdG9ncmFtIG9mICUgaW5mYW50cyBsYWNraW5nIG1lYXNsZXMgaW1tdW5pemF0aW9uIikgKyAKICB4bGFiKCIlIG9mIGluZmFudHMiKSArIAogIHlsYWIoIkNvdW50IikgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKCmBgYHtyfQpwbG90PC1nZ3Bsb3QoZGF0YT1DT1ZJRF80LGFlcyh4PURlYXRoX3JhdGUseT1NZWFzbGVzXzIwMTgsCiAgICAgICAgICAgICAgICAgICAgICAgIHNpemU9UmVjb3ZlcmVkX3BlcmNlbnRhZ2UsdGV4dD1Db3VudHJ5LlJlZ2lvbikpICsKICBnZW9tX3BvaW50KGNvbG9yPSJibGFjayIsZmlsbD1yZ2IoMjM3LzI1NSwxMDUvMjU1LDM3LzI1NSksc2hhcGU9MjEsYWxwaGE9MC42KSArCiAgc2NhbGVfc2l6ZShyYW5nZSA9IGMoMywxNSksIG5hbWU9IlJlY292ZXJlZCBcbiBwZXJjZW50YWdlIikgKwogIHRoZW1lX21pbmltYWwoKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIikgKwogIGxhYnModGl0bGU9IiUgaW5mYW50cyBsYWNraW5nIG1lYXNsZXMgaW1tdW5pemF0aW9uIFZzLiBmYXRhbGl0eSByYXRlIFxuIGFuZCBwcm9wb3J0aW9uIG9mIHJlY292ZXJlZCIsCiAgICAgICB4PSJGYXRhbGl0eSByYXRlICglKSIsCiAgICAgICB5PSIlIG9mIGluZmFudHMiKQoKZ2dwbG90bHkocGxvdCx0b29sdGlwID0gYygidGV4dCIpLHdpZHRoPTc1MCkKYGBgCgoKIyBGaXR0aW5nIGEgcmVncmVzc2lvbiBtb2RlbAoKVHJhbnNmb3JtaW5nIHdpdGggbG4gYW5kIGNvbnZlcnRpbmcgdGVtcGVyYXR1cmUgYXMga2VsdmluOgpgYGB7cn0KTW9kMTwtbG0obG9nKENPVklEXzMkQ2FzZXNfbWlsbGlvbil+bG9nKENPVklEXzMkWWVhcl8yMDE4KStsb2coQ09WSURfMyRNZWFzbGVzXzIwMTgpKwogICAgICAgICAgIGxvZyhDT1ZJRF8zJEV4cGVuZGl0dXJlXzIwMTYpK2xvZyhDT1ZJRF8zJEF2Z19JUV90ZW1wZXJhdHVyZSsyNzMuMTUpKQpzdW1tYXJ5KE1vZDEpCmBgYAoKU3RlcHdpc2Ugd2l0aCBBSUMgY3JpdGVydGlvbjoKYGBge3J9Ck1vZDI8LXN0ZXAoTW9kMSxkaXJlY3Rpb24gPSAiYm90aCIpCmBgYAoKYGBge3J9CnN1bW1hcnkoTW9kMikKYGBgCgpOb3JtYWxpdHkgb2YgcmVzaWR1YWxzOgpgYGB7cn0KaGlzdChNb2QyJHJlc2lkdWFscykKc2hhcGlyby50ZXN0KE1vZDIkcmVzaWR1YWxzKQpgYGAKClByZWRpY3Rpb24gcG93ZXI6IHNlcGFyYXRlIGJldHdlZW4gdHJhaW5pbmcgYW5kIHRlc3Rpbmc6CmBgYHtyfQpzZXQuc2VlZCgxNzk4MTkpClNhbXBsZSA8LSBzYW1wbGUoMTpsZW5ndGgoQ09WSURfMyRDYXNlc19taWxsaW9uKSxsZW5ndGgoQ09WSURfMyRDYXNlc19taWxsaW9uKSowLjIwKQp0LnRlc3Rpbmc8LSBDT1ZJRF8zW1NhbXBsZSxdCnQudHJhaW5pbmc8LSBDT1ZJRF8zWy1TYW1wbGUsXQpgYGAKClRyYW5zZm9ybSB0aGUgdHJhaW5pbmcgYW5kIHRlc3RpbmcgdmFyaWFibGVzIGFzIGJlZm9yZToKYGBge3J9CnQudHJhaW5pbmc8LXQudHJhaW5pbmcgJT4lIG11dGF0ZShDYXNlc19taWxsaW9uX2xvZz1sb2coQ2FzZXNfbWlsbGlvbiksSERJX2xvZz1sb2coWWVhcl8yMDE4KSwKICAgICAgICAgICAgICAgICAgICAgIEdEUF9sb2c9bG9nKEV4cGVuZGl0dXJlXzIwMTYpLAogICAgICAgICAgICAgICAgICAgICAgVGVtcGVyYXR1cmVfbG9nX2tlbHZpbj1sb2coQXZnX0lRX3RlbXBlcmF0dXJlKzI3My4xNSkpIAoKdC50cmFpbmluZzwtdC50cmFpbmluZ1ssMTQ6MTddCgp0LnRlc3Rpbmc8LXQudGVzdGluZyAlPiUgbXV0YXRlKENhc2VzX21pbGxpb25fbG9nPWxvZyhDYXNlc19taWxsaW9uKSxIRElfbG9nPWxvZyhZZWFyXzIwMTgpLAogICAgICAgICAgICAgICAgICAgICAgR0RQX2xvZz1sb2coRXhwZW5kaXR1cmVfMjAxNiksCiAgICAgICAgICAgICAgICAgICAgICBUZW1wZXJhdHVyZV9sb2dfa2VsdmluPWxvZyhBdmdfSVFfdGVtcGVyYXR1cmUrMjczLjE1KSkgCgp0LnRlc3Rpbmc8LXQudGVzdGluZ1ssMTQ6MTddCmBgYAoKRml0IHRoZSBzYW1lIG1vZGVsIHdpdGggdHJhaW5pbmcKYGBge3J9Ck1vZDM8LWxtKENhc2VzX21pbGxpb25fbG9nfi4sIGRhdGE9dC50cmFpbmluZykKc3VtbWFyeShNb2QzKQpgYGAKCkVycm9yIGZ1bmN0aW9uczoKYGBge3J9CiMgUmVzaWR1YWwgU3VtIG9mIFNxdWFyZSAoUlNTKQpSU1M8LWZ1bmN0aW9uKFByZWQsQWN0dWFsKSB7CiAgc3M8LXN1bSgoQWN0dWFsLVByZWQpXjIpCiAgcmV0dXJuKHNzKQp9CgojIFJlc2lkdWFsIFN0YW5kYXJkIEVycm9yIChSU0UpClJTRTwtZnVuY3Rpb24oUHJlZCxSZWFsLE51bVByZWQpIHsKICBOPC1sZW5ndGgoUmVhbCktTnVtUHJlZC0xICAKICBzczwtc3FydCgoMS9OKSpSU1MoUHJlZCxSZWFsKSkKICByZXR1cm4oc3MpCn0KIyBNZWFuIFNxdWFyZWQgRXJyb3IgCk1TRSA8LSBmdW5jdGlvbihQcmVkLEFjdHVhbCkgewogIE48LWxlbmd0aChBY3R1YWwpCiAgc3M8LSgxL04pKlJTUyhQcmVkLEFjdHVhbCkKICByZXR1cm4oc3MpCn0KCiMgUmVsYXRpdmUgZXJyb3IKUmVsYXRpdmVFcnJvcjwtZnVuY3Rpb24oUHJlZCxBY3R1YWwpIHsKICBzczwtc3VtKGFicyhBY3R1YWwtUHJlZCkpL3N1bShhYnMoQWN0dWFsKSkKICByZXR1cm4oc3MpCn0KYGBgCgpQcmVkaWN0aW9uOgpgYGB7cn0KUHJlZDwtcHJlZGljdChNb2QzLHQudGVzdGluZykKYGBgCgpFcnJvcnM6CmBgYHtyfQpSU1NfTW9kMzwtUlNTKFByZWQsdC50ZXN0aW5nJENhc2VzX21pbGxpb25fbG9nKQpSU0VfTW9kMzwtUlNFKFByZWQsdC50ZXN0aW5nJENhc2VzX21pbGxpb25fbG9nLGRpbSh0LnRlc3RpbmcpWzJdLTEpCk1TRV9Nb2QzPC1NU0UoUHJlZCx0LnRlc3RpbmckQ2FzZXNfbWlsbGlvbl9sb2cpClJlbGF0aXZlRXJyb3JfTW9kMzwtUmVsYXRpdmVFcnJvcihQcmVkLHQudGVzdGluZyRDYXNlc19taWxsaW9uX2xvZykKCk1vZDNfRXJyb3JzPC1jKFJTU19Nb2QzLFJTRV9Nb2QzLE1TRV9Nb2QzLFJlbGF0aXZlRXJyb3JfTW9kMykKYGBgCgpOb3csIGEgbW9kZWwgd2l0aG91dCB0ZW1wZXJhdHVyZToKYGBge3J9CnQudHJhaW5pbmcgPC0gdC50cmFpbmluZyAlPiUgc2VsZWN0KC1UZW1wZXJhdHVyZV9sb2dfa2VsdmluKQp0LnRlc3RpbmcgPC0gdC50ZXN0aW5nICU+JSBzZWxlY3QoLVRlbXBlcmF0dXJlX2xvZ19rZWx2aW4pCmBgYAoKYGBge3J9Ck1vZDQ8LWxtKENhc2VzX21pbGxpb25fbG9nfi4sIGRhdGE9dC50cmFpbmluZykKc3VtbWFyeShNb2Q0KQpgYGAKClByZWRpY3Rpb246CmBgYHtyfQpQcmVkPC1wcmVkaWN0KE1vZDQsdC50ZXN0aW5nKQpgYGAKCkVycm9yczoKYGBge3J9ClJTU19Nb2Q0PC1SU1MoUHJlZCx0LnRlc3RpbmckQ2FzZXNfbWlsbGlvbl9sb2cpClJTRV9Nb2Q0PC1SU0UoUHJlZCx0LnRlc3RpbmckQ2FzZXNfbWlsbGlvbl9sb2csZGltKHQudGVzdGluZylbMl0tMSkKTVNFX01vZDQ8LU1TRShQcmVkLHQudGVzdGluZyRDYXNlc19taWxsaW9uX2xvZykKUmVsYXRpdmVFcnJvcl9Nb2Q0PC1SZWxhdGl2ZUVycm9yKFByZWQsdC50ZXN0aW5nJENhc2VzX21pbGxpb25fbG9nKQoKTW9kNF9FcnJvcnM8LWMoUlNTX01vZDQsUlNFX01vZDQsTVNFX01vZDQsUmVsYXRpdmVFcnJvcl9Nb2Q0KQpgYGAKCkNyZWF0ZSBhIHJhZGFycGxvdDoKYGBge3J9CkVycm9yczwtcmJpbmQoTW9kM19FcnJvcnMsTW9kNF9FcnJvcnMpCgpyb3duYW1lcyhFcnJvcnMpPC1jKCJNb2RlbCB3aXRoIHRlbXBlcmF0dXJlIiwiTW9kZWwgd2l0aG91dCB0ZW1wZXJhdHVyZSIpCgpjb2xuYW1lcyhFcnJvcnMpPC1jKCJSZXNpZHVhbCBTdW0gb2YgU3F1YXJlIiwiUmVzaWR1YWwgU3RhbmRhcmQgRXJyb3IiLCJNZWFuIFNxdWFyZWQgRXJyb3IiLCJSZWxhdGl2ZSBlcnJvciIpCgpFcnJvcnM8LWFzLmRhdGEuZnJhbWUoRXJyb3JzKQoKbWF4aW11bTwtYXBwbHkoRXJyb3JzLDIsbWF4KQoKbWluaW11bTwtYXBwbHkoRXJyb3JzLDIsbWluKQoKRXJyb3JzPC1yYmluZChtaW5pbXVtLEVycm9ycykKCkVycm9yczwtcmJpbmQobWF4aW11bSxFcnJvcnMpCmBgYAoKYGBge3J9CnJhZGFyY2hhcnQoRXJyb3JzLG1heG1pbj1UUlVFLGF4aXN0eXBlPTQsYXhpc2xhYmNvbD0ic2xhdGVncmF5NCIsCiAgICAgICAgICAgY2VudGVyemVybz1GQUxTRSxzZWc9OCxjZ2xjb2w9ImdyYXk2NyIsCiAgICAgICAgICAgcGNvbD1jKCJkb2RnZXJibHVlMiIsImZpcmVicmljazIiLCJkYXJrb3JhbmdlMiIsImRhcmtvcmNoaWQyIiksCiAgICAgICAgICAgcGx0eT0xLAogICAgICAgICAgIHBsd2Q9MywKICAgICAgICAgICB0aXRsZT0iRXJyb3IgY29tcGFyaXNvbiIpCgpsZWdlbmRhIDwtbGVnZW5kKDEuNSwxLCBsZWdlbmQ9YygiV2l0aCB0ZW1wZXJhdHVyZSIsIldpdGhvdXQgdGVtcGVyYXR1cmUiKSwKICAgICAgICAgICAgICAgICBzZWcubGVuPS0xLjQsCiAgICAgICAgICAgICAgICAgdGl0bGU9IkVycm9ycyIsCiAgICAgICAgICAgICAgICAgcGNoPTIxLCAKICAgICAgICAgICAgICAgICBidHk9Im4iICxsd2Q9MywgeS5pbnRlcnNwPTEsIGhvcml6PUZBTFNFLAogICAgICAgICAgICAgICAgIGNvbD1jKCJkb2RnZXJibHVlMiIsImZpcmVicmljazIiLCJkYXJrb3JhbmdlMiIsImRhcmtvcmNoaWQyIikpCmBgYAoKCgoK